package com.easymin.weixin.controller.v5.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * HTTP客户端请求响应类
 * 
 * @author zhangxiaojun
 *
 */
public class HttpClient{

	private static Logger logger = LoggerFactory.getLogger(HttpClient.class);


	/**
	 * HTTPS POST 请求[默认30秒超时]
	 * @param url 请求地址
	 * @param params 参数
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpsPOST(String url, String params) throws KeyManagementException, NoSuchAlgorithmException,
			NoSuchProviderException, IOException, InterruptedException {
		return HttpsRequest_(url, "POST", params, 30 * 1000);
	}

	/**
	 * HTTP POST 请求[默认30秒超时]
	 * @param url 请求地址
	 * @param params 参数
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpPOST(String url, String params) throws KeyManagementException, NoSuchAlgorithmException,
			NoSuchProviderException, IOException, InterruptedException {
		return HttpRequest_(url, "POST", params, 30 * 1000);
	}

	/**
	 * HTTPS GET 请求[默认30秒超时]
	 * @param url 请求地址
	 * @param params 参数
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpsGET(String url, String params) throws KeyManagementException, NoSuchAlgorithmException,
			NoSuchProviderException, IOException, InterruptedException {
		return HttpsRequest_(url, "GET", params, 30 * 1000);
	}

	/**
	 * HTTP GET 请求[默认30秒超时]
	 * @param url 请求地址
	 * @param params 参数
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpGET(String url, String params) throws KeyManagementException, NoSuchAlgorithmException,
			NoSuchProviderException, IOException, InterruptedException {
		return HttpRequest_(url, "GET", params, 30 * 1000);
	}

	/**
	 * HTTPS POST 请求
	 * @param url 请求地址
	 * @param params 参数
	 * @param timeout 超时时间
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpsPOST(String url, String params, Integer timeout) throws KeyManagementException,
			NoSuchAlgorithmException, NoSuchProviderException, IOException, InterruptedException {
		return HttpsRequest_(url, "POST", params, timeout);
	}

	/**
	 * HTTP POST 请求
	 * @param url 请求地址
	 * @param params 参数
	 * @param timeout 超时时间
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpPOST(String url, String params, Integer timeout) throws KeyManagementException,
			NoSuchAlgorithmException, NoSuchProviderException, IOException, InterruptedException {
		return HttpRequest_(url, "POST", params, timeout);
	}

	/**
	 * HTTPS GET 请求
	 * @param url 请求地址
	 * @param params 参数
	 * @param timeout 超时时间
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpsGET(String url, String params, Integer timeout) throws KeyManagementException,
			NoSuchAlgorithmException, NoSuchProviderException, IOException, InterruptedException {
		return HttpsRequest_(url, "GET", params, timeout);
	}

	/**
	 * HTTP GET 请求
	 * @param url 请求地址
	 * @param params 参数
	 * @param timeout 超时时间
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpGET(String url, String params, Integer timeout) throws KeyManagementException,
			NoSuchAlgorithmException, NoSuchProviderException, IOException, InterruptedException {
		return HttpRequest_(url, "GET", params, timeout);
	}

	/**
	 * HTTPS请求
	 * @param url 请求地址
	 * @param method 请求方式
	 * @param params 参数
	 * @param timeout 超时时间
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpsRequest(String url, String method, String params, Integer timeout)
			throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, IOException,
			InterruptedException {
		return HttpsRequest_(url, method, params, timeout);
	}

	/**
	 * HTTPS请求
	 * @param url 请求地址
	 * @param method 请求方式
	 * @param params 参数
	 * @param timeout 超时时间
	 * @return 请求结果
	 * @throws KeyManagementException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static String HttpRequest(String url, String method, String params, Integer timeout)
			throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, IOException,
			InterruptedException {
		return HttpRequest_(url, method, params, timeout);
	}

	/**
	 * 获取HTTPS的URL连接
	 * @param url 请求地址
	 * @return HTTPS连接
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws KeyManagementException
	 * @throws IOException
	 */
	private static HttpsURLConnection GetHttpsURLConn(String url, String method)
			throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException, IOException {
		TrustManager[] tm = GetX509TrustManager();
		SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
		sslContext.init(null, tm, new SecureRandom());
		SSLSocketFactory ssf = sslContext.getSocketFactory();
		URL connUrl = new URL(url);
		HttpsURLConnection conn = (HttpsURLConnection) connUrl.openConnection();
		conn.setSSLSocketFactory(ssf);
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.setUseCaches(false);
		conn.setRequestMethod(method.toUpperCase());
		return conn;
	}

	/**
	 * 获取HTTP的URL连接
	 * @param url 请求地址
	 * @return HTTPS连接
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws KeyManagementException
	 * @throws IOException
	 */
	private static HttpURLConnection GetHttpURLConn(String url, String method)
			throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException, IOException {
		URL mediaUrl = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) mediaUrl.openConnection();
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.setUseCaches(false);
		conn.setRequestMethod(method.toUpperCase());
		return conn;
	}

	/**
	 * 获取连接响应数据
	 * @param conn 连接对象
	 * @return 连接的响应数据
	 * @throws IOException
	 */
	private static String GetResponseData(HttpURLConnection conn) throws IOException {
		logger.info("[获取响应数据：开始获取响应数据...]");
		InputStream inputStream = conn.getInputStream(); // 将返回的输入流转换成字符串
		InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
		BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
		String line = null;
		StringBuffer buffer = new StringBuffer();
		while ((line = bufferedReader.readLine()) != null) {
			buffer.append(line);
		}
		bufferedReader.close();
		inputStreamReader.close();
		inputStream.close();
		inputStream = null;
		conn.disconnect();
		logger.info("[获取响应数据：获取响应数据完成]");
		logger.info("[请求完成]");
		String result = buffer.toString();
		return result;
	}

	/**
	 * HTTPS请求
	 * @param url 请求地址
	 * @param method 请求方式
	 * @param params 请求参数
	 * @param timeout 请求超时时间
	 * @return 请求结果
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws KeyManagementException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static String HttpsRequest_(String url, String method, String params, Integer timeout) 
			throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException, IOException, InterruptedException {
		HttpsURLConnection conn = GetHttpsURLConn(url, method);
		if (timeout != null) {
			logger.info("[设置超时：" + timeout + "]");
			conn.setConnectTimeout(timeout);
			conn.setReadTimeout(timeout);
			logger.info("[设置超时成功]");
		}
		if ("GET".equalsIgnoreCase(method)) {
			conn.connect();
		}
		if (params != null) { // 当有数据需要提交时
			OutputStream outputStream = conn.getOutputStream();
			outputStream.write(params.getBytes("UTF-8"));
			outputStream.flush();
			outputStream.close();
		}
		return GetResponseData(conn);
	}

	/**
	 * HTTP 请求
	 * @param url 请求地址
	 * @param method 请求方式
	 * @param params 请求参数
	 * @param timeout 超时时间
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchProviderException
	 * @throws KeyManagementException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static String HttpRequest_(String url, String method, String params, Integer timeout) 
			throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException, IOException, InterruptedException {
		HttpURLConnection conn = GetHttpURLConn(url, method);
		if (timeout != null) {
			logger.info("[设置超时：" + timeout + "]");
			conn.setConnectTimeout(timeout);
			conn.setReadTimeout(timeout);
			logger.info("[设置超时成功]");
		}
		if ("GET".equalsIgnoreCase(method)) {
			conn.connect();
		}
		if (params != null) { // 当有数据需要提交时
			OutputStream outputStream = conn.getOutputStream();
			outputStream.write(params.getBytes("UTF-8"));
			outputStream.flush();
			outputStream.close();
		}
		return GetResponseData(conn);
	}

	/**
	 * 通过URL下载文件
	 * @param url 请求地址
	 * @param savePath 保存地址
	 * @param saveName 保存名称
	 * @param fileType 文件类型
	 * @return 文件保存路径
	 * @throws IOException
	 */
	public static String DownloadByUrl(String url, String savePath, String saveName, String fileType) throws IOException {
		savePath = savePath.replace("/", File.separator);
		if (!savePath.endsWith(File.separator))
			savePath += File.separator;
		File file = new File(savePath);
		if (!file.exists()) {
			file.mkdirs();
		}
		URL mediaUrl = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) mediaUrl.openConnection();
		InputStream is = conn.getInputStream();
		String filePath = savePath + saveName + "." + fileType; // 最后的文件路径
		logger.info("[文件全路径：" + filePath + "]");
		OutputStream os = new FileOutputStream(filePath);
		byte[] bs = new byte[1024];
		int len;
		while ((len = is.read(bs)) != -1) {
			os.write(bs, 0, len);
		}
		os.close();
		is.close();
		return filePath;
	}

	/**
	 * 获取一个用于https请求的证书管理器
	 * @return
	 */
	private static TrustManager [] GetX509TrustManager () {
		X509TrustManager x509 = new X509TrustManager() {
			@Override
			public X509Certificate[] getAcceptedIssuers() {
				// TODO Auto-generated method stub
				return null;
			}
			@Override
			public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
				// TODO Auto-generated method stub
			}
			@Override
			public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
				// TODO Auto-generated method stub
			}
		};
		TrustManager[] tm = { x509 };
		return tm; 
	}

}
